#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>

// this should be enough
static char buf[65536] = {};
static char code_buf[65536 + 128] = {}; // a little larger than `buf`
static char code_format[128] =
"#include <stdio.h>\n "
"int main() {"
"unsigned result = %s;"
"printf(\"%%u\", result);"
"return 0; }";

static int bufpo;
static int genround;

static uint32_t choose(uint32_t b){
	uint32_t randint = rand()%b;
//	printf("randchoose: %d at %d \n",randint,b);
	return randint;
}


static char gen_num(){
//	printf("gen_num\n");
	char op;
	switch(choose(9)){
	case 0: op ='0';break;
	case 1: op ='1';break;
	case 2: op ='2';break;
	case 3: op ='3';break;
	case 4: op ='4';break;
	case 5: op ='5';break;
	case 6: op ='6';break;
	case 7: op ='7';break;
	case 8: op ='8';break;
	case 9: op ='9';break;
	default: op = '1';
	}
 return op;
}

/*
static int randintlen;
static char* gen_32num(){
static char str[5];
uint32_t num = choose(65536);
//printf("randnumber=%d\n",num);
if (num<10){
randintlen = 1;
}
else if (num>=10 && num <99){
randintlen = 2;
}
else if (num  >= 100 && num < 999){
randintlen = 3;
}
else if (num >= 1000 && num <9999){
randintlen = 4;
}
else randintlen = 5;


int i = randintlen;
do{
	i--;
	str[i] = num%10+48;
	num /= 10;
}while(i);
	
//printf("randchar:%s\n",str);
return str;
}*/


static char gen_rand_op(){
char op;
	switch(choose(4)){
		case 0: op ='+';break;
		case 1: op ='-';break;
		case 2: op ='*';break;
		case 3: op ='/';break;
		default : op = '+';
	}
//	printf("select op %d\n",op);
	return op;
}

static void gen_rand_expr() {
  genround+=1;
  if(genround<65335){
 	 switch(choose(3)){
  		case 0: if(bufpo < 65336){
			/*char* str;
			str = gen_32num();
			for (int i =0;i<randintlen;i++){
				buf[bufpo]=str[i];
				bufpo+=1;
			}*/
			buf[bufpo] = gen_num();
			bufpo+=1;
//			printf("case0:buf[%d] = %d \n",bufpo-1,buf[bufpo-1]);
			break;}
			else break;
		case 1: if(bufpo < 65336)
			{
				buf[bufpo]='(';			
				bufpo+=1;
//				printf("case1,buf[%d]=%d\n",bufpo-1,buf[bufpo-1]);
				gen_rand_expr();
				buf[bufpo]=')';
				bufpo += 1;
					break;
			}
			else break;
		default:if(bufpo < 65336){
			gen_rand_expr();
			buf[bufpo] = gen_rand_op();
			bufpo+=1;
			gen_rand_expr();
//			printf("case3\n");
			break;}
			else break;
 	 }
  }
//  printf("random expr = %s\n",buf);
}

int main(int argc, char *argv[]) {
  int seed = time(0);
  srand(seed);
  int loop = 1;
  if (argc > 1) {
    sscanf(argv[1], "%d", &loop);
  //  printf("argv[1] = %d,arvg[2] = %s\nd",argv[1],argv[2]);
  }
  int i;
  for (i = 0; i < loop; i ++) {
    bufpo = 0;
    genround = 0;
    unsigned int len = strlen(buf);
//    printf("buf lenght:%ld\n",strlen(buf));
    for(unsigned int i =0;i < len;i++)
    {
	    buf[i] = '\0';
    }
//    printf("after init buf:%s\n",buf);   //init buf
    gen_rand_expr();
//    printf("buf = %s\n",buf);
//    char test[4]={'1','+','3','\0'};
    sprintf(code_buf, code_format,buf);

    FILE *fp = fopen("/tmp/.code.c", "w");
    assert(fp != NULL);
    fputs(code_buf, fp);
    fclose(fp);

    int ret = system("gcc /tmp/.code.c -o /tmp/.expr");
    if (ret != 0) continue;

    fp = popen("/tmp/.expr", "r");
    assert(fp != NULL);

    int result;
    fscanf(fp, "%d", &result);
    pclose(fp);

    printf("%u %s\n", result, buf);
  }
  return 0;
}
